﻿////////////////////////////////////////////////////////////////////////////////////////////////////
// file:	Test\TestRepeat.cs
//
// summary:	隔离级别可重复读及更低，会出现“幻读”现象
//                     A事务读取了两次数据，在这两次的读取过程中B事务添加了数据，A事务的这两次读取出来的集合不一样。
////////////////////////////////////////////////////////////////////////////////////////////////////

using System;
using System.Linq;
using System.Threading;
using System.Transactions;
using Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using NUnit.Framework;
using TestTransaction.Domain;

namespace TestTransaction.Test
{
    public class TestRepeat : TestBase
    {
        private AutoResetEvent _toWriteEvent = new AutoResetEvent(false);
        private AutoResetEvent _toReadEvent = new AutoResetEvent(false);

        [Test]
        public void Repeat()
        {
            ThreadPool.QueueUserWorkItem(data => {
                Read();  //启动线程读
            });
            ThreadPool.QueueUserWorkItem(data => {
                Write();  //启动线程写
            });

            Thread.Sleep(6000);

        }

        private void Read()
        {
            using (var transactionScope = new TransactionScope(TransactionScopeOption.Required,
                new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead }))
            {
                using (var context = _autofacServiceProvider.GetService<OpenAuthDBContext>())
                {
                    Console.WriteLine($"事务B：第一次取到的条数:【{context.Users.Count()}】--{DateTime.Now.ToString("HH:mm:ss fff")}");
                }

                _toWriteEvent.Set();  //模拟多线程切换，这时切换到写线程，复现幻读
                _toReadEvent.WaitOne();

                using (var context = _autofacServiceProvider.GetService<OpenAuthDBContext>())
                {
                    Console.WriteLine($"事务B：第二次读取到的条数:【{context.Users.Count()}】--{DateTime.Now.ToString("HH:mm:ss fff")}");
                }
            }

        }

        private void Write()
        {
            _toWriteEvent.WaitOne();

            using (var scope = new TransactionScope(TransactionScopeOption.Required,
                     new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
            {
                Console.WriteLine($"事务A：新增一条--{DateTime.Now.ToString("HH:mm:ss fff")}");
                using (var context = _autofacServiceProvider.GetService<OpenAuthDBContext>())
                {
                    var id = GenerateId.ShortStr();
                    context.Users.Add(new User { Id = id, Account = id, Status = 0, Name = id, CreateTime = DateTime.Now});
                    context.SaveChanges();
                }
                scope.Complete();
                Console.WriteLine($"事务A：完成新增--{DateTime.Now.ToString("HH:mm:ss fff")}");
                _toReadEvent.Set();
            }
        }
    }
}
